<h1 id="finalization">Finalization</h1>

<h2>Overview</h2>

<p>Duktape supports object finalization as a custom feature.  A finalizer
is called when an object is about to be freed, so that application code
can e.g. free native resources associated with the object.  The finalizer
can be either an ECMAScript function or a Duktape/C function.  However,
ECMAScript finalizers may interact badly with script timeouts, see below.</p>

<p>See <a href="http://wiki.duktape.org/HowtoFinalization.html">How to use finalization</a>
for examples.</p>

<h2>Getting and setting the current finalizer</h2>

<p>An object which has an internal <code>_Finalizer</code> property in its
prototype chain (or in the object itself) is subject to finalization before
being freed.  The internal property should not be accessed directly, but can
be read/written using the following:</p>
<ul>
<li><code>Duktape.fin(obj)</code> (ECMAScript) or
    <code>duk_get_finalizer()</code> (C)
    gets the current finalizer.</li>
<li><code>Duktape.fin(obj, fn)</code> (ECMAScript) or
    <code>duk_set_finalizer()</code> (C)
    sets the current finalizer.</li>
</ul>

<h2>Finalizer function arguments and return value</h2>

<p>The finalizer function is called with two arguments:</p>
<ul>
<li>The object being finalized.</li>
<li>A boolean flag indicating if the object is being forcibly freed as part
    of heap destruction.  This argument was added in Duktape 1.4.0:
    <ul>
    <li>If <code>false</code> (normal case), the finalizer may rescue the object
        by creating a live reference to the object before returning and the
        finalizer is guaranteed to be called again later (heap destruction at
        the latest).</li>
    <li>If <code>true</code> (forced finalization in heap destruction), the
        object cannot be rescued and will be forcibly freed after the finalizer
        finishes.  Native resources should be freed without expecting any further
        calls into the finalizer.</li>
    </ul>
    </li>
</ul>

<p>The return value of a finalizer is ignored.  Any errors thrown by the
finalizer are also silently ignored.</p>

<h2>Finalizer execution guarantees</h2>

<p>The main finalizer guarantees are:</p>
<ul>
<li>Finalizers are executed for unreachable objects detected by reference
    counting or mark-and-sweep.  The finalizer may not execute immediately,
    however, not even when reference counting detects that the object became
    unreachable.</li>
<li>Finalizers are also executed for all remaining objects, regardless of
    their reachability status, when a Duktape heap is destroyed.</li>
<li>A finalizer is called exactly once, at the latest when the heap is
    destroyed, unless the object is rescued by making it reachable again.
    An object may be rescued by its own finalizer, or by another object's
    finalizer when mark-and-sweep finalizes a set of objects.  For example,
    if <code>X.ref = Y</code>, and both X and Y become unreachable, it's
    possible for Y's finalizer to run, and later on X's finalizer to rescue
    both X and Y.</li>
<li>An object may be rescued an arbitrary number of times; the finalizer
    is called exactly once for each "rescue cycle".  Even with this
    guarantee in place, it's best practice for a finalizer to be re-entrant
    and carefully avoid e.g. freeing a native resource multiple times if
    re-entered.</li>
<li>A finalizer is not executed for a Proxy object, but is executed for
    the plain target object.  This ensures that a finalizer isn't executed
    multiple times when Proxy objects are created.</li>
</ul>

<p>Together these guarantee that a finalizer gets executed at some point
before a heap is destroyed, which allows native resources (such as sockets
and files) to be freed reliably.  There are a few exceptions to this guarantee,
see below for more discussion:</p>
<ul>
<li>Heap destruction finalizer sanity limit may cause a finalizer not to
    be executed.</li>
<li>When a script timeout is being propagated out of the current callstack,
    ECMAScript finalizers will immediately rethrow the script timeout error.
    Duktape/C finalizers will execute normally.</li>
<li>If Duktape runs out of memory (despite emergency GC) when trying to call a
    finalizer, the call error is silently ignored and the finalizer will be
    skipped.</li>
<li>When an object is finalized by mark-and-sweep but becomes unreachable
    before the next mark-and-sweep round has a change to detect the rescue,
    the object's finalizer will not be executed.</li>
</ul>

<p>When the Duktape heap is being destroyed there are a few limitations for
finalizer behavior:</p>
<ul>
<li>Finalizers are executed for all finalizable objects in the heap,
    including reachable objects.</li>
<li>Finalizers cannot rescue objects; the semantics for a "rescue" would be
    ambiguous.  The finalizer's second argument is <code>true</code> when
    called during heap destruction to indicate rescue is not possible.</li>
<li>A finalizer can create new finalizable objects and these objects will also
    be finalized.  For example, a finalizer may post a HTTP notification of
    an object destruction which may use native network resources with their
    own finalizers.  However, there's a sanity limit to this process to ensure
    runaway finalizers cannot prevent a heap from being destroyed.</li>
<li>The finalizer sanity algorithm is version specific, see
    <a href="http://wiki.duktape.org/HowtoFinalization.html">How to use finalization</a>.
    The algorithm allows the number of finalizable objects to grow initially,
    but it must decrease in a reasonable time or the finalization process is
    aborted, which may cause some native resource leaks.</li>
</ul>

<h2>Other current limitations</h2>

<ul>
<li>When script execution timeout
(<code>DUK_USE_EXEC_TIMEOUT_CHECK</code>)
is used and a timeout occurs, it's possible for an ECMAScript finalizer to start
running but immediately fail due to a script timeout.  If this is a concrete
concern, use a Duktape/C native finalizer instead which will run normally even
when propagating a timeout.</li>
<li>The context (Duktape thread) executing the finalizer can currently be any
    coroutine in the heap.  This must be taken into account in sandboxing.</li>
<li>Finalizers cannot currently yield.</li>
</ul>
